package cn.echisan.springbootjwtdemo.utils;

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import io.jsonwebtoken.ExpiredJwtException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.util.Date;

/**
 * Created by echisan on 2018/6/23
 */

public class NimbusdsJwtTokenUtils {
    public static final String TOKEN_PREFIX = "Bearer ";
    private static final Logger LOGGER = LoggerFactory.getLogger(NimbusdsJwtTokenUtils.class);
    private static final String ISS = "echisan";

    // 角色的key
    private static final String ROLE_CLAIMS = "rol";

    // 过期时间是3600秒，即是1个小时
    private static final long EXPIRATION = 300L;

    // 选择了记住我之后的过期时间为7天
    private static final long EXPIRATION_REMEMBER = 1000 * 60 * 60 * 24 * 7L;

    /**
     * 公共秘钥－保存在服务端，客户端是不知道该秘钥的，防止被攻击。(signature)
     */
    private static final byte[] SECRET = "jwtsecretdemo000000000000000000000000000000000000004854647864564186456iiuo".getBytes();


    /**
     * 初始化head部分的数据为(第一部分)
     * {
     * "alg":"HS256",
     * "type":"JWT"
     * }
     */
    private static final JWSHeader HEADER = new JWSHeader(JWSAlgorithm.HS512, JOSEObjectType.JWT, null, null, null, null, null, null, null, null, null, null, null);


    // 创建token
    public static String createToken(String username, String role, boolean isRememberMe) {
        long expiration = isRememberMe ? EXPIRATION_REMEMBER : EXPIRATION;

        try {
            /**
             * 1.创建一个32-byte的密匙
             */
            MACSigner macSigner = new MACSigner(SECRET);
            /**
             * 2. 建立payload 载体
             */
            JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                    .subject(username)
                    .issuer(ISS)
                    .issueTime(new Date())
                    .expirationTime(new Date(System.currentTimeMillis() + expiration))
                    .claim(ROLE_CLAIMS, role)
                    .build();

            /**
             * 3. 建立签名
             */
            SignedJWT signedjwt = new SignedJWT(HEADER, claimsSet);
            signedjwt.sign(macSigner);

            /**
             * 4. 生成token
             */
            return signedjwt.serialize();
        } catch (KeyLengthException e) {
            e.printStackTrace();
        } catch (JOSEException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 校验token
     *
     * @param token
     * @return
     */
    public static boolean vaildToken(String token) {
        try {
            SignedJWT jwt = SignedJWT.parse(token);
            JWSVerifier verifier = new MACVerifier(SECRET);
            //校验是否有效
            return jwt.verify(verifier);
        } catch (KeyLengthException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (JOSEException e) {
            e.printStackTrace();
        }
        return false;
    }

    // 从token中获取用户名
    public static String getUsername(String token) {
        try {
            return getTokenBody(token).getSubject();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 获取用户角色
    public static String getUserRole(String token) {
        try {
            return (String) getTokenBody(token).getClaim(ROLE_CLAIMS);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 是否已过期
    public static boolean isExpiration(String token) {
        try {
            return getTokenBody(token).getExpirationTime().before(new Date());
        } catch (ExpiredJwtException | ParseException e) {
            return true;
        }
    }

    private static JWTClaimsSet getTokenBody(String token) throws ParseException {
        return SignedJWT.parse(token)
                .getJWTClaimsSet();
    }
}
